package cool.taomu.toolkit.stock.service

import java.time.LocalDateTime
import java.util.ArrayList
import java.util.List
import org.eclipse.xtend.lib.annotations.Accessors

class StockBuyingPointStatisticsService {
	// 数据记录类
	@Accessors
	static class StockRecord {
		LocalDateTime date;
		String code;
		Double M5;
		Double M10;
		Double M20;
		Double macdDif;
		Double macdDea;
		Double close;
		Double bbi;
		Double bollUpper;
		Double bollLower;
		Double ema5;
		Double ema10;
		Double rsi6;
		Double k;
		Double d;
		Double j;
		Double low;

		new(LocalDateTime date, String code, Double M5, Double M10, Double M20, Double macdDif, Double macdDea,
			Double close, Double low, Double bbi, Double bollUpper, Double bollLower, Double ema5, Double ema10,
			Double rsi6, Double k, Double d, Double j) {
			this.date = date;
			this.code = code;
			this.M5 = M5;
			this.M10 = M10;
			this.M20 = M20;
			this.macdDif = macdDif;
			this.macdDea = macdDea;
			this.close = close;
			this.low = low;
			this.bbi = bbi;
			this.bollUpper = bollUpper;
			this.bollLower = bollLower;
			this.ema5 = ema5;
			this.ema10 = ema10;
			this.rsi6 = rsi6;
			this.k = k;
			this.d = d;
			this.j = j;
		}
	}

	// 信号类
	@Accessors
	static class Signal {
		LocalDateTime date;
		String code;
		String signalType;
		String type;
		LocalDateTime signalDate; // 均线买入点的日期
		Double price; // 均线买入点的价格

		new(LocalDateTime date, String code, String signalType, String type, LocalDateTime signalDate, Double price) {
			this.date = date;
			this.code = code;
			this.signalType = signalType;
			this.signalDate = signalDate;
			this.price = price;
			this.type = type;
		}
	}

	def List<Signal> findMacdAndOtherSignals(List<StockRecord> records, int nDays) {
		var List<Signal> signals = new ArrayList();

		for (var int i = 1; i < records.size(); i++) {
			var StockRecord prev = records.get(i - 1);
			var StockRecord curr = records.get(i);

			// 判断 MACD 买入点（快线上穿慢线）
			var boolean isMacdBuy = prev.macdDif < prev.macdDea && curr.macdDif > curr.macdDea;

			if (isMacdBuy) {
				// 记录 MACD 买入点的日期和价位
				var LocalDateTime macdBuyDate = curr.date;
				var Double macdBuyPrice = curr.close;

				// 找到 MACD 买入点后，检查前后 n 天的其他指标买入点
				var int startIndex = Math.max(0, i - nDays); // 前 n 天
				var int endIndex = Math.min(records.size() - 1, i + nDays); // 后 n 天
				for (var int j = startIndex; j <= endIndex; j++) {
					var StockRecord record = records.get(j);

					// 检查 BBI 买入点
					if (record.low > record.bbi) {
						signals.add(new Signal(record.date, record.code, "BBI Buy", "macd", macdBuyDate, macdBuyPrice));
					}

					// 检查 BOLL 买入点
					if (record.close < record.bollLower) {
						signals.add(
							new Signal(record.date, record.code, "BOLL Buy", "macd", macdBuyDate, macdBuyPrice));
					}

					// 检查 EMA 买入点
					if (record.close > record.ema5 || record.close > record.ema10) {
						signals.add(new Signal(record.date, record.code, "EMA Buy", "macd", macdBuyDate, macdBuyPrice));
					}

					// 检查 RSI 买入点
					if (record.rsi6 !== null && record.rsi6 < 30) {
						signals.add(new Signal(record.date, record.code, "RSI Buy", "macd", macdBuyDate, macdBuyPrice));
					}

					// 检查 KDJ 买入点
					if (record.k !== null && record.d !== null && record.j !== null && record.k > record.d &&
						record.j > 0) {
						signals.add(new Signal(record.date, record.code, "KDJ Buy", "macd", macdBuyDate, macdBuyPrice));
					}
					// 检查 MA 买入点
					if ((record.M5 !== null && record.M10 !== null && record.M5 > record.M10) ||
						(record.M5 !== null && record.M20 !== null && record.M5 > record.M20)) {
						signals.add(new Signal(record.date, record.code, "MA Buy", "macd", macdBuyDate, macdBuyPrice));
					}
				}
			}
		}
		return signals;
	}

	def List<Signal> findMacdAndOtherSellSignals(List<StockRecord> records, int nDays) {
		var List<Signal> signals = new ArrayList();

		for (var int i = 1; i < records.size(); i++) {
			var StockRecord prev = records.get(i - 1);
			var StockRecord curr = records.get(i);

			// 判断 MACD 卖出点（快线下穿慢线）
			var boolean isMacdSell = (prev.macdDif !== null && prev.macdDea !== null && curr.macdDif !== null &&
				curr.macdDea !== null && prev.macdDif > prev.macdDea && curr.macdDif < curr.macdDea);

			if (isMacdSell) {
				// 记录 MACD 卖出点的日期和价位
				var LocalDateTime macdSellDate = curr.date;
				var Double macdSellPrice = curr.close;

				// 找到 MACD 卖出点后，检查前后 n 天的其他指标卖出点
				var int startIndex = Math.max(0, i - nDays); // 前 n 天
				var int endIndex = Math.min(records.size() - 1, i + nDays); // 后 n 天
				for (var int j = startIndex; j <= endIndex; j++) {
					var StockRecord record = records.get(j);

					// 检查 BBI 卖出点
					if (record.bbi !== null && record.close < record.bbi) {
						signals.add(
							new Signal(record.date, record.code, "BBI Sell", "MACD", macdSellDate, macdSellPrice));
					}

					// 检查 BOLL 卖出点
					if (record.bollUpper !== null && record.close > record.bollUpper) {
						signals.add(
							new Signal(record.date, record.code, "BOLL Sell", "MACD", macdSellDate, macdSellPrice));
					}

					// 检查 EMA 卖出点
					if ((record.ema5 !== null && record.close < record.ema5) ||
						(record.ema10 !== null && record.close < record.ema10)) {
						signals.add(
							new Signal(record.date, record.code, "EMA Sell", "MACD", macdSellDate, macdSellPrice));
					}

					// 检查 RSI 卖出点
					if (record.rsi6 !== null && record.rsi6 > 70) {
						signals.add(
							new Signal(record.date, record.code, "RSI Sell", "MACD", macdSellDate, macdSellPrice));
					}

					// 检查 KDJ 卖出点
					if (record.k !== null && record.d !== null && record.j !== null && record.k < record.d &&
						record.j < 0) {
						signals.add(
							new Signal(record.date, record.code, "KDJ Sell", "MACD", macdSellDate, macdSellPrice));
					}

					// 检查 MA 卖出点
					if ((record.M5 !== null && record.M10 !== null && record.M5 < record.M10) ||
						(record.M5 !== null && record.M20 !== null && record.M5 < record.M20)) {
						signals.add(
							new Signal(record.date, record.code, "MA Sell", "MACD", macdSellDate, macdSellPrice));
					}
				}
			}
		}

		return signals;
	}
}
